Laufschrift hor. mit DL-Manipulation

← Zurück zum Forum

Hallo, ich wollte hier noch einmal ein paar Überlegungen reinstellen betreffend Laufschrift / bzw. Feinscrolling horizontal. Der Profiprogrammierer kennt das sicherlich zur genüge und wir hatten hier im Forum auch schon auf sehr gut Seiten im Internet hingewiesen, wo man alles sehr gut nachlesen kann. Hier an dieser Stelle kommt jetzt aber ein kleines Programm - wie üblich in Assembler unter MADS - wo ich eine einfache Laufschrift mit "unendlichem Text" in die obere Zeile des Bildschirmes anzeigen lassen werde. Die Schrift läuft feingescrollt von rechts nach links durch, der Grobscroll soll durch Displaylistmanipulation stattfinden. Das ist etwas komplizierter und aufwendiger, macht aber natürlich Sinn, wenn man das erweitert auf das Scrollen des gesamten Bildschirmes. Wenn es tatsächlich wie im Beispiel nur eine Zeile sein soll, dann kann man natürlich den Grobscroll auch durch umkopieren einfach durchführen, das belastet die CPU nicht nennenswert.

Zunächst nehmen wir ANTIC 2 und bauen die Displaylist entsprechend auf. Der Bildschirm startet nicht bei 40000 sondern bei 40040. Ich brauche eine Leerzeile von 40000 bis 40040. Zeile 2 startet dann ab 40166 damit ich genügend Platz habe ... das erkläre ich später. Das grobe Prinzip: Ich hole die Buchstaben vom Text und printe sie 2x auf den Bildschirm, einmal in den "sichtbaren" Bereich und einmal in einen unsichtbaren Bereich. Die Displaylist manipuliere ich nun bei jedem Grobscroll um 1 und schiebe somit den angezeigten Bereich über den Speicher.. nach 80 Verschiebungen wird die Displayliste wieder auf den Anfangswert geschrieben und alles startet von vorne.

Anbei der Code:

    org $2000


hscrolx   .by 00

laufschrx1 = 240



dlist   
      .by 112,112,112
      .by 66+16
dl1     .by 104,156   ;40040
      .by 66+16
dl2     .by 230,156   ;40166
:22     .by 2+16
      .by 65
      .wo dlist   

start

      mwa #dlist 560  

      mwa #copy1 laufschrx1
      ldx #0

@   
      mva hscrolx $d404
      jsr wartes
      jsr wartes
      jsr laufschrift
      dec hscrolx
      jmp @-


      run start

      .proc laufschrift

      #if .byte hscrolx=#0
      inc dl1
@
      ; ------ ab hier jeweils einen Buchstaben holen -------
      ldy #0
      lda (laufschrx1),y
      cmp #3    ; # Text Ende
      bne @+
      mwa #copy1 laufschrx1
      jmp @-
@
      sta 40085,x
      sta 40005,x
      inx
      cpx #80
      bcc @+
      ldx #0
      mva #104 dl1
@
      clc
      lda laufschrx1
      adc #1
      sta laufschrx1
      lda laufschrx1+1
      adc #0
      sta laufschrx1+1
      mva #4 hscrolx
      #end

      rts
      .endp
      .proc wartes
      lda 20
wa   
      cmp 20
            beq wa 

            rts
          .endp 


;===============================================================
; Laufschrift Daten
copy1 
    .byte "Heute ist ein wirklich schoener Tag, die Sonne scheint und es wird endlich waermer. Der Fruehling kommt und bald ist Sommer, wo wir wieder mit T-Shirt rausgehen koennen....          " 
    .byte "hier kann jetzt noch ganz viel Text stehen. Die Grenze des Textes ist praktisch nicht limitiert und kann weit ueber die 255 Byte-Grenze hinausgehen.             "
    .byte "Die Textlimitation ergibt sich natuerlich aus dem Speicher ......  ;-)    #"
;===============================================================

;===============================================================

Jeder darf hier frei optimieren - bzw. gibt es einfachere Lösungen? LG Peter

AntwortZitat

nur als Hinweis, die Speicherzellen sind in Dezimal angegeben, nicht Hexa-Dezimal! (ich dachte erst, du programmierst auf dem ST 🙂 )

Super Anleitung! Solche Code-Schnipsel sind immer sehr hilfreich!

keine PN's mehr! Bitte per email kontaktieren! atari1450xld©mega-hz.de

AntwortZitat

Warum kopierst du die Daten jedes Mal? Allokier einfach eine Bildschirmzeile zusätzlich direkt hinter deinem String und kopiere die ersten 40 (plus 3) Zeichen dorthin. Dann kannst du die DL einfach innerhalb deines Strings laufen lassen.

    org $2000


hscrolx   .by 04      ; =0 waere eine sofortige Inkrementierung von dl1 beim Programmstart


dlist   
      .by 112,112,112
      .by 66+16
dl1     .wo dupli1-3    ;dupli1-3 weil die ersten 3 Zeichen uebersprungen werden
      .by 66+16
dl2     .by 230,156   ;40166
:22     .by 2+16
      .by 65
      .wo dlist   

start
; Die ersten 40+x Bytes hinten an den Text anhängen für den "Wrap-Around" 
      ldx #39+3   ; 40 Zeichen pro Zeile plus 3 Zeichen Überhang
@     lda copy1,X
      sta dupli1,X
      dex
      bpl @-

      mwa #dlist 560  

@   
      mva hscrolx $d404
      jsr wartes
      jsr wartes
      jsr laufschrift
      dec hscrolx
      jmp @-


      run start

      .proc laufschrift

      #if .byte hscrolx=#0
      inc dl1
      bne @+
      inc dl1+1
@
      mva #4 hscrolx

      lda dl1     ; Ende des Scrollbuffers erreicht?
      cmp #<dupli1
      bne endproc
      lda dl1+1
      cmp #>dupli1
      bne endproc

      mwa #copy1 dl1    ;> => DL wieder auf Anfang setzen
      #end

endproc   
      rts
      .endp

      .proc wartes
      lda 20
wa   
      cmp 20
            beq wa 

            rts
          .endp 


;===============================================================
; Laufschrift Daten
; Darf NICHT über eine 4KB-Grenze laufen
copy1 
    .byte "Heute ist ein wirklich schoener Tag, die Sonne scheint und es wird endlich waermer. Der Fruehling kommt und bald ist Sommer, wo wir wieder mit T-Shirt rausgehen koennen....          " 
    .byte "hier kann jetzt noch ganz viel Text stehen. Die Grenze des Textes ist praktisch nicht limitiert und kann weit ueber die 255 Byte-Grenze hinausgehen.             "
    .byte "Die Textlimitation ergibt sich natuerlich aus dem Speicher ......  ;-)    "
; Platz fuer den Textanfang, der am Ende nochmal stehen muss, wegen des "Wrap-Arounds".
dupli1    .ds 40+3

;===============================================================

;===============================================================

Die 3 Zeichen zusätzlich brauchst du wegen des Überhangs beim Softscroll. Interessant ist auch, dass die ersten 3 Zeichen nicht angezeigt werden. Beim Programmstart steht also nicht "Heute ist..." auf dem Bildschirm, sondern "te ist...". Deshalb initialisiere ich die DL beim Start auf 3 Bytes vor dem Ende - und damit kurz vor dem Warp-Around.

AntwortZitat

Ich spare mir bei Gfx 0, 1 oder 2 (hier haben wir ja meist direkt die Zeichen vom Font) das Kopieren der ganzen Zeichen normalerweise immer und ändere in der DL einfach die Adresse, ab wo der Scroller eingeblendet wird. So kann man bis zu $1000 Zeichen im Scroller haben und muss nicht viel kopieren.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

Hi,

ich hab da ein paar Fragen zu dem Assembler.

@ ist wohl eine Sprungmarke und mit einem Branchbefehl gefolgt von + oder - springt man zur nächsten oder vorherigen?

:22 .by 2+16

Was bedeutet die ":22" ?

    mwa #dlist 560

Ist mwa =

LDA #<num

STA REG

LDA #>num

STA REG+1

Das heißt das "w" in dem Befehl steht für "word"?

    mva hscrolx $d404

Das wäre dann

LDA hscrolx

STA $D404

?

    #if .byte hscrolx=#0

Was bewirkt das hier? Ist das Programmcode oder konditionales Assemblieren?

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

@ ist wohl eine Sprungmarke und mit einem Branchbefehl gefolgt von + oder - springt man zur nächsten oder vorherigen?

Korrekt

:22 .by 2+16

Was bedeutet die ":22" ?

22-fache Wiederholung, also 22-mal die 18.

    mwa #dlist 560

Das heißt das "w" in dem Befehl steht für "word"?

Korrekt

    mva hscrolx $d404

?

Korrekt

    #if .byte hscrolx=#0

Was bewirkt das hier? Ist das Programmcode oder konditionales Assemblieren?

Das weiß ich nicht.

AntwortZitat
    #if .byte hscrolx=#0

Was bewirkt das hier? Ist das Programmcode oder konditionales Assemblieren?

Das weiß ich nicht.

Hier wird alles zwischen #if und #end ausgeführt, wenn die Bedingung stimmt. Also der komplette Block:

         #if .byte hscrolx=#0
         inc dl1

@

         ; ------ ab hier jeweils einen Buchstaben holen -------
         ldy #0
         lda (laufschrx1),y
         cmp #3      ; # Text Ende
         bne @+
         mwa #copy1 laufschrx1
         jmp @-

@

         sta 40085,x
         sta 40005,x
         inx
         cpx #80
         bcc @+
         ldx #0
         mva #104 dl1

@

         clc
         lda laufschrx1
         adc #1
         sta laufschrx1
         lda laufschrx1+1
         adc #0
         sta laufschrx1+1
         mva #4 hscrolx
         #end

Im Prinzip könnte man das auch so lösen:

         lda hscrolx

         bne raus

;hier nun alles von inc dli bis zum #end und statt #end das:

raus

         rts

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

Die Möglichkeit einfach ohne den Text reinzukopieren und nur die Speicherstellen entsprechend zu manipulieren ist natürlich viel eleganter und CPU sparender, ich wollte das Beispiel aber möglichst einfach halten.

Die Option mit #if ... #end finde ich (Basic angelehnt) recht einfach und übersichtlich, die einfache #if ... #end verbraucht dabei nicht mehr Speicher und wird entsprechend gleich schnell übersetzt von Mads! Kann man also bedenkenlos benutzen. man kann es auch komplizierter mit .or und .and verschachteln, das verbraucht aber mehr Rechenkapazität. Das mache ich nur zur Übersicht mal primär und wandel das dann später um.

Hexa oder Dezimal? In der Regel finde ich persönlich dezimal eingängiger, in manchen Situationen ist dei Schreibweise in Hex besser für die Programmierung und ab und an ist es Bit-weise besser... ich verwende das also unterschiedlich!

AntwortZitat

Ich habe mich vor ein paar Jahren auf einer Fujiama mal an einer Laufschrift versucht und obwohl ich der Meinung war, alles richtig gemacht zu haben hat die irgendwie gezittert.

Deshalb hab ich gerade mal Deinen Quellcode in WUDSN (da bin ich mal wieder völlig aus der Übung) reinkopiert und bekomme beim Assemblieren die Fehlermeldung:

Illegal label name, must start with '@','?', or a letter. Laufschrift.asm /Laufschrift line 1 Problem

Das bezieht sich auf den ORG $2000 Befehl.

Vielleicht benutzt WUDSN ja den falschen Assembler, aber ich finde nicht wo definiert ist, welcher von den konfigurierten verwendet werden soll.

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

Das bezieht sich auf den ORG $2000 Befehl.

Hast du beim Copy/Paste evtl. die Leerzeichen vor dem ORG vergessen, sodass es in der erste Spalte beginnt?

AntwortZitat

Da sind 12 Leerzeichen ...

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

Hallo Erhard, ich nutze MADS

Das @ ist ein Sprunglabel. Nimm einfach zB sprung1 statt @ und dann müsste es gehen.

AntwortZitat

Solange ich nicht herausbekomme, wie ich in WUDSN einstelle, welcher der vorhandenen Assembler benutzt werden soll komme ich hier wohl nicht weiter.

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

Ich kenne die Videos und hab die sogar alle lokal verfügbar.

Mein Problem ist, daß ich aufgrund der seltenen Verwendung von WUDSN (maximal 1x pro Jahr) ich erst jedes mal alle Videos durchackern müßte, damit ich WUDSN wieder benutzen kann. Bei der langen Pause schmeißt mein Hirn immer alle Infos aus dem Speicher. Wenn ich mich dann wieder einigermaßen eingearbeitet habe ist die verfügbare Zeit meist aufgebraucht. :-/

Unter Editors / File Associations hab ich die Einstellung intuitiv nicht vermutet - aber jetzt gefunden und angepaßt -> klappt. Danke!

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

Und dann tu ich auch mal meinen Senf - ähm Code - dabei.

Die Änderung für feines und grobes Scrolling erfolgen im verzögerten "Vertical Blank Interrupt".

Ich weiß jetzt nicht genau, wie lange ich an den paar Zeilen gesessen hab, aber ich hab mir echt einen dabei abgebrochen.

Und dann kann der 6502 noch nicht einmal INC (zp),Y ...

;Code im MADS Format

ZPDLST = $D4                          ;ZP-Zwischenpseicher für Adresse der DisplayList
SDLIST = $0230
SETVBV = $E45C
XITVBV = $E462
HSCROL = $D404
;
;
            ORG $4000
FINESCROL   .BYTE 0

VBL_ROUTINE LDX FINESCROL             ;Wird im verzoegerten VBL aufgerufen
            DEX
            TXA
            AND #3
            TAX
            CPX #3
            BNE NO_INC
            LDY #1
            CLC                       ;Grobes Scrolling immer dann, wenn bei
            LDA (ZPDLST),Y            ;feinem Scrolling der Wechsel von
            ADC #1                    ;Verschieben auf nicht Verschieben ansteht
            STA (ZPDLST),Y
NO_INC      STX FINESCROL
            STX HSCROL
X_VBL       JMP XITVBV                ;Alle Register wiederherstellen und RTI

MAIN        LDA SDLIST                ;Kopiere DisplayList Adresse in ZP
            STA ZPDLST                ;fuer indirekte Adressierung
            LDA SDLIST+1
            STA ZPDLST+1

            LDY #0                    ;Anpassung der DL
            LDA #$52                  ;Ersetzt die 3 Leerzeilen
            STA (ZPDLST),Y            ;durch eine GR.0 Zeile mit LMS
            INY
            LDA #<TXT
            STA (ZPDLST),Y
            INY
            LDA #>TXT
            STA (ZPDLST),Y

            LDA #3                    ;Startwert für 'keine Verschiebung'
            STA FINESCROL
            LDA #7                    ;Set deferred VBL
            LDX # >VBL_ROUTINE
            LDY # <VBL_ROUTINE
            JMP SETVBV

            ORG $5000
TXT :48     .byte " "                 ;48 x SPACE
            .byte "Bei aktiviertem H-Scrolling verwendet ANTIC die 48 Zeichen Bildschirmbreite. "
            .byte "An beiden Bildschirmraendern kommen je 4 Zeichen hinzu. "
            .byte "Bei nur 40 Leerzeichen sind rechts die ersten 4 Zeichen vom Text sichtbar."

            RUN MAIN

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat

Ohne das jetzt zu testen - sitze eh gerade in der U-Bahn und kann es nicht - sieht das irgendwie merkwürdig aus. Du startest Dein Programm und der letzte Code macht ein JMP setvbv? Geht das wirklich so? Dachte setvbv endet mit einem rts. Stürzt das Programm nicht ab?

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

pps schrieb am 04.09.2026 14:21: Geht das wirklich so? Dachte setvbv endet mit einem rts. Stürzt das Programm nicht ab?

sollte so gehen, ist funktional identisch mit

  JSR SETVBV
  RTS

springt am Ende zum aufrufenden Programm, wahrscheinlich in das DOS zurück.

https://mastodon.social/@cstrotm https://abbuc.social

AntwortZitat

cas schrieb am 04.09.2026 14:24:

pps schrieb am 04.09.2026 14:21: Geht das wirklich so? Dachte setvbv endet mit einem rts. Stürzt das Programm nicht ab?

sollte so gehen, ist funktional identisch mit

  JSR SETVBV
  RTS

springt am Ende zum aufrufenden Programm, wahrscheinlich in das DOS zurück.

Aber wenn man das Programm einfach so beendet, ist nicht klar, ob die Laufschrift überhaupt noch läuft. Das wollte ich anmerken mit meinem Kommentar. Startet man von einem GameDOS, könnte man sehr merkwürdige Ergebnisse haben.

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo

AntwortZitat

Bei mir springt das Programm dahin zurück, von wo es aufgerufen wurde, in meinem Fall getestet mit Atari DOS 2.0, SpartaDOS 3.3 und aus Bug/65 heraus. Ich kann danach auch mit Atari DOS 2.0 bzw. SpartaDOS 3.3 oder auch im Bug/65 weiter arbeiten. Der Scroller läuft und bleibt natürlich bei Diskaktivität kurz stehen, da der verzögerte VBI da nicht abgearbeitet wird.

paste_1.png

Natürlich muß was zum Zurückspringen da sein. Ein GameDOS sieht eine Rückkehr nicht vor und wenn man die Datei auf einen Altirra zieht, der im Selbsttest des Atari steht klappt das natürlich auch nicht, da müßte das Programm vermutlich in einer Endlosschleife bleiben, was dem Sinn der Interruptverwendung aber widerspricht.

Natürlich könnte das Programm auch mit einem Sprung über DOSVEC enden, aber auch da muß was Sinnvolles in DOSVEC drinstehen.

Darf ich fragen, in welcher Umgebung es nicht funktioniert?

Nachtrag: gerade noch unter OSS OS/A+ v1.2, OSS OS/A+ v2.0, OSS DOS XL 2.30 und DOS II+/D v6.1 getestet. Die ersten beiden DOS beachten offenbar die RUN Adresse nicht und starten das Programm einfach mit dem ersten Byte, was natürlich nicht funktioniert. Wenn man da aber per RUN manuell springt klappt es auch da. Mit OSS DOS XL 2.30 klappt es direkt.

Also gelernt: am besten vorne im Programm auch noch ein JMP MAIN rein.

Jede Info, die zu Hause auf meinem Rechner liegt habe ich unterwegs nicht verfügbar. Jede Info, die im Netz liegt finde ich nicht wieder, wenn ich sie benötige.

AntwortZitat